package com.chatplus.application.web.resolver;

import com.chatplus.application.common.crypto.Crypto;
import com.chatplus.application.common.crypto.RequestMessageDecryptor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.core.MethodParameter;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor;

import java.util.Objects;

@SuppressWarnings("NullableProblems")
public class CryptoMethodArgumentResolver implements HandlerMethodArgumentResolver {
    private final RequestMessageDecryptor requestMessageDecryptor;
    private final ServletModelAttributeMethodProcessor servletModelAttributeMethodProcessor;

    public CryptoMethodArgumentResolver(RequestMessageDecryptor requestMessageDecryptor) {
        this.requestMessageDecryptor = requestMessageDecryptor;
        this.servletModelAttributeMethodProcessor = new ServletModelAttributeMethodProcessor(false);
    }

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(Crypto.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

        Crypto crypto = parameter.getParameterAnnotation(Crypto.class);
        String parameterName = Objects.requireNonNull(crypto).name();
        if (StringUtils.isBlank(parameterName)) {
            parameterName = parameter.getParameterName();
        }

        if (parameterName != null) {
            if (String.class.equals(parameter.getParameterType())) {
                String cipherText = webRequest.getParameter(parameterName);
                if (StringUtils.isNotBlank(cipherText)) {
                    return requestMessageDecryptor.decrypt(cipherText);
                }
            }
            //bean对象类型
            else if(!BeanUtils.isSimpleProperty(parameter.getParameterType())){
                Object argument = servletModelAttributeMethodProcessor.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
                ReflectionUtils.doWithFields(parameter.getParameterType(), (field -> {
                    field.setAccessible(true);
                    Object fieldValue = ReflectionUtils.getField(field, argument);
                    if (fieldValue instanceof String) {
                        fieldValue = requestMessageDecryptor.decrypt((String) fieldValue);
                    }
                    ReflectionUtils.setField(field, argument, fieldValue);
                }), (field -> field.isAnnotationPresent(Crypto.class)));

                return argument;
            }
        }

        return null;
    }
}
